package config

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type ViewFunc func(http.ResponseWriter, *http.Request)

func basicAuth(f ViewFunc, user, passwd []byte) ViewFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		basicAuthPrefix := "Basic "
		auth := r.Header.Get("Authorization")
		if strings.HasPrefix(auth, basicAuthPrefix) {
			payload, err := base64.StdEncoding.DecodeString(
				auth[len(basicAuthPrefix):],
			)
			if err == nil {
				pair := bytes.SplitN(payload, []byte(":"), 2)
				if len(pair) == 2 && bytes.Equal(pair[0], user) &&
					bytes.Equal(pair[1], passwd) {
					f(w, r)
					return
				}
			}
		}
		w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
		w.WriteHeader(http.StatusUnauthorized)
	}
}
func WriteToConfig(k string, v interface{}) error {
	config_json, err := os.ReadFile("./config.json")
	if err != nil {
		log.Printf("[Config] Read config.json failed\r\n")
		return err
	}
	var config map[string]interface{}
	json.Unmarshal(config_json, &config)
	config[k] = v
	str, err := json.Marshal(config)
	if err != nil {
		log.Printf("[Config] json Marshal failed\r\n")
		return err
	}
	log.Printf("[Config] config json : %s\r\n", string(str))
	err = os.WriteFile("./config.json", str, 0644)
	if err != nil {
		log.Printf("[Config] Failed to write config.json, err: %v\r\n", err)
		return err
	}
	return nil
}
func GetOutboundIP() (net.IP, error) {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		log.Printf("[GetOutboundIP] err:%v\r\n", err)
		return nil, err
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*net.UDPAddr)

	return localAddr.IP, nil
}

func http_index(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		tmpl, err := template.ParseFiles("./config/index.html")
		if err != nil {
			log.Fatal(err)
		}
		err = tmpl.Execute(w, "")
		if err != nil {
			log.Fatal(err)
		}
	}
}
func http_admin(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		tmpl, err := template.ParseFiles("./config/admin.html")
		if err != nil {
			log.Fatal(err)
		}
		err = tmpl.Execute(w, "")
		if err != nil {
			log.Fatal(err)
		}
	}
}
func http_wifi(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		ssid := r.FormValue("ssid")
		pass := r.FormValue("pass")
		io.WriteString(w, fmt.Sprintf("WiFi Setting Successful\nssid:%s\npass:%s", ssid, pass))
		log.Printf("[Config] WiFi Setting Successful, ssid : %s, pass : %s\r\n", ssid, pass)
		go setWPA_Config(ssid, pass)
	}
}
func http_rm_setting(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		enable_log, err := strconv.Atoi(r.FormValue("detail_log"))
		if err != nil {
			io.WriteString(w, "Detail log enable failed\n")
			log.Printf("[http_rmSave] Detail log enable failed\r\n")
			return
		}
		enable_base64, err := strconv.Atoi(r.FormValue("base64"))
		if err != nil {
			io.WriteString(w, "Base64 enable failed\n")
			log.Printf("[http_rmSave] Base64 enable failed\r\n")
			return
		}

		//WriteToConfig(detail_log_key, enable_log)
		//WriteToConfig(base64_key, enable_base64)

		io.WriteString(w, fmt.Sprintf("Run mode setting success\nDetail log:%d\nBase 64:%d", enable_log, enable_base64))
		log.Printf("[http_rmSave] BLE setting successful, Detail log:%d Base 64:%d", enable_log, enable_base64)
	}
}

func http_ble_setting(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		ble_name := r.FormValue("ble_name")
		ble_max_conn, err := strconv.Atoi(r.FormValue("ble_max_conn"))
		if err != nil {
			io.WriteString(w, "BLE setting fail\nMax Connection should set by number")
			log.Printf("[Config] BLE setting fail Max Connection should set by number\r\n")
			return
		}
		if ble_max_conn < 1 || ble_max_conn > 8 {
			io.WriteString(w, fmt.Sprintf("Invaild Max Connection number\nshould be in range from 1 to 8\ncurrent setting is %d", ble_max_conn))
			return
		}
		//WriteToConfig(ble_name_key, ble_name)
		//WriteToConfig(max_conn_key, ble_max_conn)

		io.WriteString(w, fmt.Sprintf("BLE setting successful\nBLE Name:%s\nMax Conn:%d", ble_name, ble_max_conn))
		log.Printf("[Config][ble_setting] BLE setting successful, BLE Name:%s, Max Conn:%d\r\n", ble_name, ble_max_conn)
	}
}
func setWPA_Config(ssid string, pass string) {
	wpa_config, err := os.ReadFile("/etc/wpa_supplicant/wpa_supplicant.conf")
	if err != nil {
		log.Printf("[setWPA] Read wpa_supplicant failed\r\n")
		return
	}
	wpa_str := string(wpa_config)
	old_ssid, old_pass, _ := parseWPA_Config(wpa_str)
	wpa_str = strings.Replace(wpa_str, old_ssid, ssid, -1)
	wpa_str = strings.Replace(wpa_str, old_pass, pass, -1)
	log.Printf("[setWPA] Write to wpa_supplicant:\r\n%s\r\n", wpa_str)
	err = os.WriteFile("/etc/wpa_supplicant/wpa_supplicant.conf", []byte(wpa_str), 0644)
	if err != nil {
		log.Printf("[Config] Failed to write config.json, err: %v\r\n", err)
		return
	}
	log.Printf("[setWPA] reconnect to WiFi\r\n")

}
func getWPA_Config() (ssid string, pass string, err error) {
	wpa_config, err := os.ReadFile("/etc/wpa_supplicant/wpa_supplicant.conf")
	if err != nil {
		log.Printf("[getWPA_Config] Read wpa_supplicant failed\r\n")
		return "", "", err
	}
	wpa_str := string(wpa_config)
	ssid, pass, _ = parseWPA_Config(wpa_str)
	log.Printf("[getWPA_Config] SSID:%s, PASS:%s\r\n", ssid, pass)
	return ssid, pass, nil
}
func parseWPA_Config(wpa_str string) (ssid string, pass string, err error) {
	ssid_index_start := strings.Index(wpa_str, "ssid=\"") + len("ssid=\"")
	ssid_index_end := strings.Index(wpa_str[ssid_index_start:len(wpa_str)-1], "\"") + ssid_index_start
	ssid = wpa_str[ssid_index_start:ssid_index_end]

	pass_index_start := strings.Index(wpa_str, "psk=\"") + len("psk=\"")
	pass_index_end := strings.Index(wpa_str[pass_index_start:len(wpa_str)-1], "\"") + pass_index_start
	pass = wpa_str[pass_index_start:pass_index_end]
	return ssid, pass, nil
}
func http_get_config(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		config_json, err := os.ReadFile("./config.json")
		if err != nil {
			log.Printf("[Config] Read config.json failed\r\n")
			return
		}
		var config map[string]interface{}
		json.Unmarshal(config_json, &config)
		cmd := exec.Command("cat", "/sys/class/net/wlan0/address") // get mac address
		stdout, err := cmd.Output()
		if err != nil {
			log.Printf("[Config] Get Mac address failed: %v\r\n", err)
			return
		}
		config["gw_mac"] = strings.ToUpper(string(stdout))
		ip, err := GetOutboundIP()
		if err == nil {
			config["gw_ip"] = ip.To4().String()
		} else {
			config["gw_ip"] = "no internet access"
		}
		ssid, pass, _ := getWPA_Config()
		config["ssid"] = ssid
		config["pass"] = pass
		str, err := json.Marshal(config)
		if err != nil {
			log.Printf("[Config] json Marshal failed\r\n")
			return
		}
		io.WriteString(w, string(str))
	}
}

func http_upload2(w http.ResponseWriter, req *http.Request) {
	mr, err := req.MultipartReader()
	if err != nil {
		return
	}
	length := req.ContentLength
	fmt.Println(length)
	for {

		part, err := mr.NextPart()
		if err == io.EOF {
			break
		}
		var read int64
		dst, err := os.OpenFile("IMG.ZIP", os.O_WRONLY|os.O_CREATE, 0777)
		if err != nil {
			return
		}
		for {
			buffer := make([]byte, 100000)
			cBytes, err := part.Read(buffer)
			if err == io.EOF {
				break
			}
			read = read + int64(cBytes)
			fmt.Printf("read: %v cBytes %v\r\n", read, cBytes)
			//var p float32
			//p = float32(read) / float32(length) * 100
			//fmt.Printf("progress: %v \r\n", p)

			dst.Write(buffer[0:cBytes])
			pr := 100 * read / length
			s := fmt.Sprintf("%d\r\n", int(pr))
			//io.WriteString(w, s)//更新后面是...
			fmt.Printf("progress: %s \r\n", s)
		}
		io.WriteString(w, "upload ok")
	}
}

func http_upload(writer http.ResponseWriter, request *http.Request) {
	log.Printf("[http_upload] start\r\n")
	request.ParseMultipartForm(32 << 20)
	file, _, err := request.FormFile("uploadfile")
	if err != nil {
		log.Printf("[http_upload] request.FormFile: %v\r\n", err)
		fmt.Fprintln(writer, err) //fmt.Fprintln(writer, "fail")

		return
	}
	defer file.Close()
	fmt.Fprintln(writer, "upload ok !")

	out, err := os.Create("./IMG.ZIP")
	wt := bufio.NewWriter(out)
	defer out.Close()
	n, err := io.Copy(wt, file)
	log.Printf("[http_upload] write %d\r\n", n)
	if err != nil {
		panic(err)
	}
	wt.Flush()

	log.Printf("[http_upload] end\r\n")
	//io.WriteString(writer, "upload ok")
	//ota.OtaHandler("")
}
func Start() {
	user := []byte("izar")
	passwd := []byte("53029625")

	mux := http.NewServeMux()
	mux.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./config/js"))))
	mux.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./config/css"))))
	mux.HandleFunc("/", http_index)
	mux.HandleFunc("/admin", basicAuth(http_admin, user, passwd))
	mux.HandleFunc("/wifi", http_wifi)
	//mux.HandleFunc("/ws", http_ws)
	mux.HandleFunc("/upload", http_upload)
	mux.HandleFunc("/ble_setting", http_ble_setting)
	mux.HandleFunc("/rm_setting", http_rm_setting)
	mux.HandleFunc("/config", http_get_config)
	http.ListenAndServe(":8079", mux)
}
